
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.order.IAcctOrderAppService;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.dto.order.*;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.profit.IChannelProfitOrderGateway;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountBindDO;
import com.hlkj.pay.infrastructure.model.order.OrderFundDO;
import com.hlkj.pay.infrastructure.model.order.OrderFundDetailDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.service.merchant.IMerchantFundAccountService;
import com.hlkj.pay.service.order.IPayOrderFundService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.openapi.order.resp.AcctPayOrderApiResp;
import com.hlkj.pay.vo.openapi.order.resp.AcctRefundOrderApiResp;
import com.hlkj.pay.vo.order.req.AcctOrderQueryParamReq;
import com.hlkj.pay.vo.order.req.AcctPayOrderParamReq;
import com.hlkj.pay.vo.order.req.AcctRefundOrderParamReq;
import com.hlkj.pay.vo.order.req.OrderAccount;
import com.hlkj.pay.vo.order.resp.acct.AcctPayOrderResp;
import com.hlkj.pay.vo.order.resp.acct.PayOrderFundResp;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2025/01/07 11:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class AcctOrderAppServiceImpl implements IAcctOrderAppService {

    private final IPayOrderFundService payOrderFundService;

    private final IPayOrderService payOrderService;

    private final IChannelProfitOrderGateway channelProfitOrderGateway;

    private final OrderNotifyHandler orderNotifyHandler;

    private final IMerchantFundAccountService merchantFundAccountService;

    private final OrderCodeUtil orderCodeUtil;

    @Override
    public CommonResult<AcctPayOrderApiResp> submitAcctOrder(@Valid AcctPayOrderParamReq acctPayOrderParamReq) {
        log.info("submitAcctOrder acctPayOrderParamReq:{}", JsonUtils.toJsonString(acctPayOrderParamReq));
        try {
            if (!StringUtils.hasText(acctPayOrderParamReq.getPayOrderNo()) && !StringUtils.hasText(acctPayOrderParamReq.getMchOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderFundDO orderFundDO = payOrderFundService.queryPayAcctInfo(null, acctPayOrderParamReq.getMchAcctOrderNo());
            if (orderFundDO != null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_EXIST);
            }
            PayOrderDO payOrderDO = null;
            if (StringUtils.hasText(acctPayOrderParamReq.getPayOrderNo())) {
                payOrderDO = payOrderService.queryPayOrder(acctPayOrderParamReq.getPayOrderNo());
            }
            else {
                String sn = LocalContext.get().getSn();
                payOrderDO = payOrderService.queryPayOrderByMerOrderNo(sn, acctPayOrderParamReq.getMchOrderNo());
            }
            if (payOrderDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
            }
            PayOrderEnums.FUND_PROCESS_TYPE fundProcessType = PayOrderEnums.FUND_PROCESS_TYPE.from(payOrderDO.getFundProcessType());
            switch (fundProcessType) {
                case MERCHANT:
                case DELAY_TIME:
                    break;
                default:
                    return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_NOT_EFFECT);
            }
            if (!PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(payOrderDO.getState())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_NOT_EFFECT);
            }
            if (!channelProfitOrderGateway.extensionExist(payOrderDO.getChannelCode())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_NOT_EFFECT);
            }
            List<OrderAccount> acctInfos = acctPayOrderParamReq.getAcctInfos();
            for(OrderAccount orderAccount:acctInfos){
                // 分账关系获取名称
                if(StrUtil.isEmpty(orderAccount.getName())){
                    List<MerchantFundAccountBindDO> accountBindDOList = merchantFundAccountService.queryAccountBindList(payOrderDO.getMchChannelCode());
                    if(CollUtil.isNotEmpty(accountBindDOList)){
                        Optional<MerchantFundAccountBindDO> optional = accountBindDOList.stream().filter(orderBindAccount->orderBindAccount.getAccountNo().equals(orderAccount.getAccountNo())).findFirst();
                        if(optional.isPresent()){
                            orderAccount.setName(optional.get().getName());
                        }
                    }
                }
            }
            Set<String> accountNos = acctInfos.stream().map(acctInfo -> acctInfo.getAccountNo()).collect(Collectors.toSet());
            if (accountNos.size() != acctInfos.size()) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
            }
            // BigDecimal db = new BigDecimal("0");
            // // 已存在的分账数据
            // List<OrderFundDetailDO> payOrderFundDb = payOrderFundService.queryPayAcctInfo(payOrderDO.getPayOrderNo());
            // if (!CollectionUtils.isEmpty(payOrderFundDb)) {
            //     db = new BigDecimal(payOrderFundDb.stream().filter(acctInfo -> !PayOrderEnums.PAY_ORDER_FUND_STATUS.FAIL.getCode().equals(acctInfo.getFundStatus()))
            //             .mapToDouble(acctInfo -> acctInfo.getAmount().doubleValue()).sum());
            // }
            // double summed = acctInfos.stream().mapToDouble(acctInfo -> MerchantUtils.stringToBigDecimal(acctInfo.getAmount()).doubleValue()).sum();
            // // 提交的分账金额与存在的分账金额不能大于订单金额
            // if (MerchantUtils.add(new BigDecimal(summed), db).compareTo(payOrderDO.getAmount()) > 0) {
            //     return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
            // }
            List<PayOrderFundDto> payOrderFundDtoList = new ArrayList<>();
            String batchNo = IdUtils.getSnowflakeNextIdStr();
            int i = 1;
            for (OrderAccount orderAccount : acctInfos) {
                PayOrderFundDto payOrderFundDto = BeanUtil.copyProperties(orderAccount, PayOrderFundDto.class);
                payOrderFundDto.setBatchNo(batchNo);
                payOrderFundDto.setBatchNoDetail(batchNo + "_" + i);
                i = i + 1;
                payOrderFundDtoList.add(payOrderFundDto);
            }
            log.info("submitAcctOrder 分账数据 :{}",JSONUtil.toJsonStr(payOrderFundDtoList));
            // 请求第三方
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.submitProfitOrder(payOrderDO, payOrderFundDtoList);
            if (PayOrderEnums.PAY_ORDER_FUND_STATUS.FAIL.getCode().equals(profitOrderResultDto.getPayOrderFundStatus().getCode())) {
                List<OrderFundDetailDO> payOrderFundRecordList = payOrderFundList(payOrderFundDtoList);
                AcctPayOrderApiResp acctPayOrderApiResp = new AcctPayOrderApiResp();
                List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(payOrderFundRecordList, PayOrderFundResp.class);
                acctPayOrderApiResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
                acctPayOrderApiResp.setBatchNo(batchNo);
                acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
                acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
                acctPayOrderApiResp.setMchAcctOrderNo(acctPayOrderParamReq.getMchAcctOrderNo());
                // 返回支付数据
                CommonResult<AcctPayOrderApiResp> error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_ERROR);
                error.setData(acctPayOrderApiResp);
                return error;
            }else{
                log.info("分账订单状态结束,进行通知 payOrderNo:{}", payOrderDO.getPayOrderNo());
                // 发送通知
                if (StringUtils.hasText(acctPayOrderParamReq.getNotifyUrl())) {
                    orderNotifyHandler.orderNotify(batchNo, 1,PayOrderEnums.ORDER_STATUS_TYPE.FUND_ORDER_STATUS);
                }
                else {
                    log.info("分账订单状态结束,没有填写回调通知地址,结束通知");
                }
            }
            // 回写数据
            payOrderFundService.addAcctPayInfo(acctPayOrderParamReq, payOrderFundDtoList, payOrderDO);
            List<OrderFundDetailDO> payOrderFundList = payOrderFundService.queryAcctDetailInfo(batchNo);
            AcctPayOrderApiResp acctPayOrderApiResp = new AcctPayOrderApiResp();
            List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(payOrderFundList, PayOrderFundResp.class);
            acctPayOrderApiResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
            acctPayOrderApiResp.setBatchNo(batchNo);
            acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            acctPayOrderApiResp.setMchAcctOrderNo(acctPayOrderParamReq.getMchAcctOrderNo());

            // 返回支付数据
            return CommonResult.success(acctPayOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<AcctRefundOrderApiResp> refundAcctOrder(@Valid AcctRefundOrderParamReq acctRefundOrderParamReq) {
        log.info("refundAcctOrder acctRefundOrderParamReq:{}", JsonUtils.toJsonString(acctRefundOrderParamReq));
        try {
            OrderFundDO refundOrderFund = payOrderFundService.queryRefundAcctInfo(null, acctRefundOrderParamReq.getMchAcctRefundOrderNo());
            if (refundOrderFund != null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_EXIST);
            }
            OrderFundDO payOrderFund = payOrderFundService.queryPayAcctInfo(acctRefundOrderParamReq.getBatchNo(), acctRefundOrderParamReq.getMchAcctOrderNo());
            if (payOrderFund == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_NOT_EFFECT);
            }
            List<OrderFundDetailDO> payOrderFundList = payOrderFundService.queryAcctDetailInfo(payOrderFund.getBatchNo());
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderFund.getPayOrderNo());
            PayOrderEnums.CHANNEL_FUND_PROCESS_TYPE fundProcessType = PayOrderEnums.CHANNEL_FUND_PROCESS_TYPE.from(payOrderDO.getChannelCode());
            List<OrderAccount> acctInfos = acctRefundOrderParamReq.getAcctInfos();
            Map<String, OrderFundDetailDO> payOrderFundMap = payOrderFundList.stream()
                    .collect(Collectors.toMap(payOrderFundDO -> payOrderFundDO.getAccountNo(), Function.identity()));

            List<RefundOrderFundDto> refundOrderFundDtoList = new ArrayList<>();
            String batchNo = IdUtils.getSnowflakeNextIdStr();
            int i = 1;
            for (OrderAccount orderAccount : acctInfos) {
                OrderFundDetailDO payOrderFundDb = payOrderFundMap.get(orderAccount.getAccountNo());
                if (payOrderFundDb == null) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_ERROR.getCode(),
                            String.format(OpenApiResultCode.MERCHANT_ACCT_ORDER_ERROR.getMsg(), orderAccount.getAccountNo()));
                }
                // 提交的金额不能大于支付的分账金额
                if (MerchantUtils.stringToBigDecimal(orderAccount.getAmount()).compareTo(payOrderFundDb.getAmount()) > 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_ORDER_NOT_EFFECT);
                }
                // orderAccount.setOrgSerialNumber(payOrderFundDb.getBatchNoDetail());
                RefundOrderFundDto refundOrderFundDto = BeanUtil.copyProperties(orderAccount, RefundOrderFundDto.class);
                refundOrderFundDto.setOrgBatchNoDetail(payOrderFundDb.getBatchNoDetail());
                refundOrderFundDto.setOrgBatchNo(payOrderFundDb.getBatchNo());
                refundOrderFundDto.setType(payOrderFundDb.getType());
                refundOrderFundDto.setBatchNo(batchNo);
                refundOrderFundDto.setBatchNoDetail(batchNo + "_" + i);
                refundOrderFundDto.setDetailId(payOrderFundDb.getDetailId());
                refundOrderFundDto.setCreateTime(payOrderFundDb.getCreateTime());
                i = i + 1;
                refundOrderFundDtoList.add(refundOrderFundDto);
            }
            // 请求第三方
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.submitProfitRefundOrder(payOrderDO, refundOrderFundDtoList);
            if (PayOrderEnums.PAY_ORDER_FUND_STATUS.FAIL.getCode().equals(profitOrderResultDto.getPayOrderFundStatus().getCode())) {
                List<OrderFundDetailDO> payOrderFundRecordList = refundOrderFundList(refundOrderFundDtoList);
                AcctRefundOrderApiResp acctPayOrderApiResp = new AcctRefundOrderApiResp();
                List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(payOrderFundRecordList, PayOrderFundResp.class);
                acctPayOrderApiResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
                acctPayOrderApiResp.setBatchNo(batchNo);
                acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
                acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
                acctPayOrderApiResp.setMchAcctOrderNo(acctRefundOrderParamReq.getMchAcctOrderNo());
                acctPayOrderApiResp.setMchAcctRefundOrderNo(acctRefundOrderParamReq.getMchAcctRefundOrderNo());
                // 返回支付数据
                CommonResult<AcctRefundOrderApiResp> error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_ERROR);
                error.setData(acctPayOrderApiResp);
                return error;
            }
            // 更新数据
            OrderFundDto orderFundDto = payOrderFundService.addAcctRefundInfo(acctRefundOrderParamReq, refundOrderFundDtoList, payOrderDO,profitOrderResultDto.getPayOrderFundStatus());
            List<OrderFundDetailDO> payOrderFundRecordList = orderFundDto.getOrderFundDetailList();
            AcctRefundOrderApiResp acctPayOrderApiResp = new AcctRefundOrderApiResp();
            List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(payOrderFundRecordList, PayOrderFundResp.class);
            acctPayOrderApiResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
            acctPayOrderApiResp.setBatchNo(batchNo);
            acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            acctPayOrderApiResp.setMchAcctOrderNo(acctRefundOrderParamReq.getMchAcctOrderNo());
            acctPayOrderApiResp.setMchAcctRefundOrderNo(acctRefundOrderParamReq.getMchAcctRefundOrderNo());
            // 返回支付数据
            return CommonResult.success(acctPayOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    List<OrderFundDetailDO> refundOrderFundList(List<RefundOrderFundDto> refundOrderFundDtos) {
        List<OrderFundDetailDO> payOrderFundList = new ArrayList<>();
        refundOrderFundDtos.stream().forEach(acctInfo -> {
            OrderFundDetailDO orderFundDetailDO = new OrderFundDetailDO();
            orderFundDetailDO.setAccountNo(acctInfo.getAccountNo());
            orderFundDetailDO.setAmount(MerchantUtils.stringToBigDecimal(acctInfo.getAmount()));
            orderFundDetailDO.setDescription(acctInfo.getDescription());
            orderFundDetailDO.setFundStatus(acctInfo.getFundStatus().getCode());
            orderFundDetailDO.setBatchNo(acctInfo.getBatchNo());
            orderFundDetailDO.setBatchNoDetail(acctInfo.getBatchNoDetail());
            orderFundDetailDO.setOrgBatchNoDetail(acctInfo.getOrgBatchNoDetail());
            orderFundDetailDO.setFailReason(acctInfo.getFailReason());
            payOrderFundList.add(orderFundDetailDO);
        });
        return payOrderFundList;
    }

    List<OrderFundDetailDO> payOrderFundList(List<PayOrderFundDto> payOrderFundDtos) {
        List<OrderFundDetailDO> payOrderFundList = new ArrayList<>();
        payOrderFundDtos.stream().forEach(acctInfo -> {
            OrderFundDetailDO orderFundDetailDO = new OrderFundDetailDO();
            orderFundDetailDO.setAccountNo(acctInfo.getAccountNo());
            orderFundDetailDO.setAmount(MerchantUtils.stringToBigDecimal(acctInfo.getAmount()));
            orderFundDetailDO.setDescription(acctInfo.getDescription());
            orderFundDetailDO.setFundStatus(acctInfo.getFundStatus().getCode());
            orderFundDetailDO.setBatchNo(acctInfo.getBatchNo());
            orderFundDetailDO.setBatchNoDetail(acctInfo.getBatchNoDetail());
            orderFundDetailDO.setFailReason(acctInfo.getFailReason());
            payOrderFundList.add(orderFundDetailDO);
        });
        return payOrderFundList;
    }

    @Override
    public CommonResult<AcctPayOrderResp> queryAcctOrder(AcctOrderQueryParamReq acctOrderParamReq) {
        log.info("queryAcctOrder acctOrderParamReq:{}", JsonUtils.toJsonString(acctOrderParamReq));
        try {
            if (!StringUtils.hasText(acctOrderParamReq.getBatchNo()) && !StringUtils.hasText(acctOrderParamReq.getMchAcctOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderFundDO payOrderFund = payOrderFundService.queryPayAcctInfo(acctOrderParamReq.getBatchNo(), acctOrderParamReq.getMchAcctOrderNo());
            if (payOrderFund == null) {
                return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
            }
            List<OrderFundDetailDO> orderFundDetailList = payOrderFundService.queryAcctDetailInfo(payOrderFund.getBatchNo());

            List<OrderFundDetailDO> collect = orderFundDetailList.stream()
                    .filter(refundOrderFundDO -> PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(refundOrderFundDO.getFundStatus())).collect(Collectors.toList());
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderFund.getPayOrderNo());
            if (!CollectionUtils.isEmpty(collect)) {
                ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.queryProfitOrder(payOrderDO, orderFundDetailList);
                List<Integer> fundStatusSet = profitOrderResultDto.getPayOrderFundList().stream().map(payOrderFundDO -> payOrderFundDO.getFundStatus())
                        .collect(Collectors.toList());
                if (fundStatusSet.size() != 1 || !PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(fundStatusSet.get(0))) {
                    orderFundDetailList = updatePayFund(profitOrderResultDto.getPayOrderFundList(), payOrderFund);
                }
            }
            AcctPayOrderResp acctPayOrderApiResp = new AcctPayOrderResp();
            List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(orderFundDetailList, PayOrderFundResp.class);
            acctPayOrderApiResp.setAccRetry(payOrderFund.getAccRetry());
            acctPayOrderApiResp.setAcctInfos(payOrderFundResps);
            acctPayOrderApiResp.setBatchNo(payOrderFund.getBatchNo());
            acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            acctPayOrderApiResp.setMchAcctOrderNo(payOrderFund.getMchAcctOrderNo());
            // 返回支付数据
            return CommonResult.success(acctPayOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<AcctRefundOrderApiResp> queryRefundAcctOrder(AcctOrderQueryParamReq acctOrderParamReq) {
        log.info("queryRefundAcctOrder acctOrderParamReq:{}", JsonUtils.toJsonString(acctOrderParamReq));
        try {
            if (!StringUtils.hasText(acctOrderParamReq.getBatchNo()) && !StringUtils.hasText(acctOrderParamReq.getMchAcctOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderFundDO refundOrderFund = payOrderFundService.queryRefundAcctInfo(acctOrderParamReq.getBatchNo(), acctOrderParamReq.getMchAcctOrderNo());
            if (refundOrderFund == null) {
                return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
            }
            List<OrderFundDetailDO> orderFundDetailList = payOrderFundService.queryAcctDetailInfo(refundOrderFund.getBatchNo());
            List<OrderFundDetailDO> collect = orderFundDetailList.stream()
                    .filter(refundOrderFundDO -> PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(refundOrderFundDO.getFundStatus())).collect(Collectors.toList());
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(refundOrderFund.getPayOrderNo());
            if (!CollectionUtils.isEmpty(collect)) {

            }
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.queryProfitRefundOrder(payOrderDO, orderFundDetailList);
            List<Integer> fundStatusSet = profitOrderResultDto.getRefundOrderFundList().stream().map(payOrderFundDO -> payOrderFundDO.getFundStatus())
                    .collect(Collectors.toList());
            if (fundStatusSet.size() != 1 || !PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(fundStatusSet.get(0))) {
                orderFundDetailList = updatePayFund(profitOrderResultDto.getRefundOrderFundList(), refundOrderFund);
            }
            AcctRefundOrderApiResp acctPayOrderApiResp = new AcctRefundOrderApiResp();
            List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(orderFundDetailList, PayOrderFundResp.class);
            acctPayOrderApiResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
            acctPayOrderApiResp.setBatchNo(refundOrderFund.getBatchNo());
            acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            acctPayOrderApiResp.setMchAcctOrderNo(refundOrderFund.getMchAcctOrderNo());
            acctPayOrderApiResp.setMchAcctRefundOrderNo(refundOrderFund.getMchAcctRefundOrderNo());
            // 返回支付数据
            return CommonResult.success(acctPayOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<AcctPayOrderResp> finishAcctOrder(AcctOrderQueryParamReq acctOrderQueryParamReq) {
        log.info("finishAcctOrder acctOrderQueryParamReq:{}", JsonUtils.toJsonString(acctOrderQueryParamReq));
        try {
            if (!StringUtils.hasText(acctOrderQueryParamReq.getBatchNo()) && !StringUtils.hasText(acctOrderQueryParamReq.getMchAcctOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderFundDO payOrderFund = payOrderFundService.queryPayAcctInfo(acctOrderQueryParamReq.getBatchNo(), acctOrderQueryParamReq.getMchAcctOrderNo());
            if (payOrderFund == null) {
                return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
            }
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderFund.getPayOrderNo());
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.finishAcctOrder(payOrderDO, payOrderFund);

            if(StrUtil.isNotEmpty(profitOrderResultDto.getRemark())){
                return CommonResult.error(0,profitOrderResultDto.getRemark());
            }

            payOrderFundService.updatePayFundStatus(payOrderFund.getId(), profitOrderResultDto.getPayOrderFundStatus());

            AcctPayOrderResp acctPayOrderApiResp = new AcctPayOrderResp();
            acctPayOrderApiResp.setBatchNo(payOrderFund.getBatchNo());
            acctPayOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            acctPayOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            acctPayOrderApiResp.setMchAcctOrderNo(payOrderFund.getMchAcctOrderNo());
            // 返回支付数据
            return CommonResult.success(acctPayOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public void payAcctOrder(PayOrderDO payOrderDO) {
        log.info("payAcctOrder payOrderNo:{}", payOrderDO.getPayOrderNo());
        try {
            if (payOrderDO.getFundProcessType() == null || PayOrderEnums.FUND_PROCESS_TYPE.NO.equals(payOrderDO.getFundProcessType())) {
                log.info("payAcctOrder 当前订单非分账订单 payOrderNo:{}", payOrderDO.getPayOrderNo());
                return;
            }
            if (!PayOrderEnums.FUND_PROCESS_TYPE.REAL_TIME.getCode().equals(payOrderDO.getFundProcessType())
                    && !PayOrderEnums.FUND_PROCESS_TYPE.MERCHANT.getCode().equals(payOrderDO.getFundProcessType())) {
                log.info("payAcctOrder 订单非实时分账结束 payOrderNo:{},fundProcessType:{}", payOrderDO.getPayOrderNo(), payOrderDO.getFundProcessType());
                return;
            }
            OrderFundDto orderFundDto = payOrderFundService.queryAcctOrderFundDtoByPayOrderNo(payOrderDO.getPayOrderNo());
            if (orderFundDto == null) {
                if (PayOrderEnums.FUND_PROCESS_TYPE.MERCHANT.getCode().equals(payOrderDO.getFundProcessType())) {
                    log.info("payAcctOrder 商户 预设默认分账 payOrderNo:{}", payOrderDO.getPayOrderNo());
                    processMerchantFundOrder(payOrderDO);
                }
                else {
                    log.info("payAcctOrder 分账数据不存在 payOrderNo:{}", payOrderDO.getPayOrderNo());
                }
                return;
            }
            // 更新为分账中 因为此部分订单可能提交订单的时候已经将分账提交信息到第三方,需要查询分账信息
            OrderFundDO orderFund = orderFundDto.getOrderFund();
            if (PayOrderEnums.SYSTEM_PROCESS_TYPE.SYSTEM.getCode().equals(orderFund.getSystemProcessType())) {
                log.info("payAcctOrder 系统自动分账订单 payOrderNo:{}", payOrderDO.getPayOrderNo());
                // 提交延迟分账信息
                processSystemFundOrder(payOrderDO, orderFundDto);
            }
            else if (PayOrderEnums.SYSTEM_PROCESS_TYPE.CHANNEL.getCode().equals(orderFund.getSystemProcessType())) {
                log.info("payAcctOrder 渠道自动分账订单 payOrderNo:{}", payOrderDO.getPayOrderNo());
                // 渠道分账 直接改状态
                payOrderFundService.updatePayFundStatus(orderFund.getId(), PayOrderEnums.PAY_ORDER_FUND_STATUS.SUCCESS);
            }

        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public CommonResult<String> delAcctDetail(String batchNoDetail) {
        OrderFundDetailDO orderFundDetailDO = payOrderFundService.queryAcctDetail(batchNoDetail);
        if(orderFundDetailDO == null){
            return CommonResult.error(0,"分账详情不存在");
        }
        payOrderFundService.delAcctDetail(batchNoDetail);
        return CommonResult.success();
    }

    /**
     * 处理系统分账
     * 
     * @param payOrderDO
     * @param orderFundDto
     */
    void processSystemFundOrder(PayOrderDO payOrderDO, OrderFundDto orderFundDto) {
        List<OrderFundDetailDO> orderFundDetailList = orderFundDto.getOrderFundDetailList();
        if (CollectionUtils.isEmpty(orderFundDetailList)) {
            log.info("payAcctOrder payOrderNo:{},fundProcessType:{},分账数据不存在 分账结束", payOrderDO.getPayOrderNo(), payOrderDO.getFundProcessType());
            return;
        }
        if (!channelProfitOrderGateway.extensionExist(payOrderDO.getChannelCode())) {
            orderFundDetailList.stream().forEach(payOrderFundDO -> {
                payOrderFundDO.setFundStatus(PayOrderEnums.PAY_ORDER_FUND_STATUS.FAIL.getCode());
                payOrderFundDO.setFailReason("当前通道不可以系统自动分账");
            });
            updatePayFund(orderFundDetailList, orderFundDto.getOrderFund());
            // 回写数据
            return;
        }
        String acctInfoJson = payOrderDO.getAcctInfoJson();
        List<PayOrderFundDto> payOrderFundDtos = new ArrayList<>();
        if (StringUtils.hasText(acctInfoJson)) {
            payOrderFundDtos = JsonUtils.parseArray(acctInfoJson, PayOrderFundDto.class);
        }
        channelProfitOrderGateway.submitProfitOrder(payOrderDO, payOrderFundDtos);
        Map<String, PayOrderFundDto> collect = payOrderFundDtos.stream().collect(Collectors.toMap(payOrderFundDto -> payOrderFundDto.getAccountNo(), Function.identity()));
        orderFundDetailList.stream().forEach(orderFundDetailDO -> {
            PayOrderFundDto payOrderFundDto = collect.get(orderFundDetailDO.getAccountNo());
            if (payOrderFundDto != null) {
                orderFundDetailDO.setFundStatus(payOrderFundDto.getFundStatus().getCode());
                orderFundDetailDO.setFailReason(payOrderFundDto.getFailReason());
            }
        });
        // 回写数据
        updatePayFund(orderFundDetailList, orderFundDto.getOrderFund());
    }

    /**
     * 处理系统分账
     * 
     * @param payOrderDO
     */
    void processMerchantFundOrder(PayOrderDO payOrderDO) {
        List<MerchantFundAccountBindDO> merchantFundAccountBindList = merchantFundAccountService.queryAccountBindList(payOrderDO.getMchChannelCode(), CommonEnum.YES_NO_TYPE.YES,
                CommonEnum.YES_NO_TYPE.YES);
        if (CollectionUtils.isEmpty(merchantFundAccountBindList)) {
            log.info("payAcctOrder 商户 预设默认分账数据不存在 payOrderNo:{}", payOrderDO.getPayOrderNo());
            return;
        }
        // PayOrderEnums.CHANNEL_FUND_PROCESS_TYPE fundProcessType = PayOrderEnums.CHANNEL_FUND_PROCESS_TYPE.from(payOrderDO.getChannelCode());
        // if (fundProcessType.isNeedFee()) {
        //     merchantFundAccountBindList = merchantFundAccountBindList.stream().filter(merchantFundAccountBind -> merchantFundAccountBind.getFee() != null)
        //             .collect(Collectors.toList());
        //     if (CollectionUtils.isEmpty(merchantFundAccountBindList)) {
        //         log.info("payAcctOrder 商户  预设默认分账数据存在有效手续费不存在 payOrderNo:{}", payOrderDO.getPayOrderNo());
        //         return;
        //     }
        // }
        List<PayOrderFundDto> payOrderFundDtoList = new ArrayList<>();
        String batchNo = IdUtils.getSnowflakeNextIdStr();
        int i = 1;
        for (MerchantFundAccountBindDO orderAccount : merchantFundAccountBindList) {
            PayOrderFundDto payOrderFundDto = BeanUtil.copyProperties(orderAccount, PayOrderFundDto.class);
            payOrderFundDto.setName(orderAccount.getName());
            payOrderFundDto.setSepaFeeRatio("0");
            payOrderFundDto.setBatchNo(batchNo);
            payOrderFundDto.setPeriodType(orderAccount.getD0());
            payOrderFundDto.setBatchNoDetail(batchNo + "_" + i);
            i = i + 1;

            if(StrUtil.isEmpty(payOrderFundDto.getAmount())&& payOrderDO.getAmount() != null
                                                   && orderAccount.getRate() != null){
                payOrderFundDto.setAmount(NumberUtil.roundStr(payOrderDO.getAmount().multiply(orderAccount.getRate()).divide(new BigDecimal(100)).doubleValue(),2));
            }
            if(StrUtil.isEmpty(payOrderFundDto.getDescription())){
                payOrderFundDto.setDescription("系统分账");
            }
            payOrderFundDtoList.add(payOrderFundDto);
        }
        log.info("payAcctOrder 商户 预设默认分账接收方信息:{}", JSONUtil.toJsonStr(payOrderFundDtoList));
        // 请求第三方
        channelProfitOrderGateway.submitProfitOrder(payOrderDO, payOrderFundDtoList);
        // 回写数据
        payOrderFundService.addAcctPayInfo(null, payOrderFundDtoList, payOrderDO);
    }

    @Override
    public void syncPayAcctOrderStatus() {
        log.info("支付分账订单同步");
        PayOrderFundQueryDto payOrderFundQueryDto = new PayOrderFundQueryDto();
        payOrderFundQueryDto.setSystemProcessType(PayOrderEnums.SYSTEM_PROCESS_TYPE.SYSTEM.getCode());
        payOrderFundQueryDto.setFundStatus(PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode());
        payOrderFundQueryDto.setFundType(CommonEnum.YES_NO_TYPE.NO.getCode());
        List<OrderFundDO> payOrderFundList = payOrderFundService.queryPayAcctInfoList(payOrderFundQueryDto);
        if (com.hlkj.framework.common.util.collection.CollectionUtils.isEmpty(payOrderFundList)) {
            log.info("当前 queryPayAcctOrderStatus 执行没有需要同步的订单");
            return;
        }
        log.info("当前 queryPayAcctOrderStatus 执行 需要同步的分账数量为 size:{}", payOrderFundList.size());
        payOrderFundList.stream().forEach(payOrderFund -> {
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderFund.getPayOrderNo());
            List<OrderFundDetailDO> orderFundDetailList = payOrderFundService.queryAcctDetailInfo(payOrderFund.getBatchNo());
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.queryProfitOrder(payOrderDO, orderFundDetailList);
            List<Integer> fundStatusSet = profitOrderResultDto.getPayOrderFundList().stream().map(payOrderFundDO -> payOrderFundDO.getFundStatus()).collect(Collectors.toList());
            if (fundStatusSet.size() == 1 && PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(fundStatusSet.get(0))) {
                return;
            }
            updatePayFund(profitOrderResultDto.getPayOrderFundList(), payOrderFund);
        });
    }

    @Override
    public void updatePayFundStatus(Long id, PayOrderEnums.PAY_ORDER_FUND_STATUS payOrderFundStatus) {
        payOrderFundService.updatePayFundStatus(id,payOrderFundStatus);
    }

    @Override
    public void syncRefundAcctOrderStatus() {
        log.info("退款分账订单同步");
        PayOrderFundQueryDto payOrderFundQueryDto = new PayOrderFundQueryDto();
        payOrderFundQueryDto.setSystemProcessType(PayOrderEnums.SYSTEM_PROCESS_TYPE.SYSTEM.getCode());
        payOrderFundQueryDto.setFundStatus(PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode());
        payOrderFundQueryDto.setFundType(CommonEnum.YES_NO_TYPE.YES.getCode());
        List<OrderFundDO> payOrderFundList = payOrderFundService.queryPayAcctInfoList(payOrderFundQueryDto);
        if (com.hlkj.framework.common.util.collection.CollectionUtils.isEmpty(payOrderFundList)) {
            log.info("当前 syncRefundAcctOrderStatus 执行没有需要同步的订单");
            return;
        }
        log.info("当前 syncRefundAcctOrderStatus 执行 需要同步的分账数量为 size:{}", payOrderFundList.size());
        payOrderFundList.stream().forEach(refundOrderFund -> {
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(refundOrderFund.getPayOrderNo());
            List<OrderFundDetailDO> orderFundDetailList = payOrderFundService.queryAcctDetailInfo(refundOrderFund.getBatchNo());
            ProfitOrderResultDto profitOrderResultDto = channelProfitOrderGateway.queryProfitRefundOrder(payOrderDO, orderFundDetailList);
            List<Integer> fundStatusSet = profitOrderResultDto.getRefundOrderFundList().stream().map(payOrderFundDO -> payOrderFundDO.getFundStatus()).collect(Collectors.toList());
            if (fundStatusSet.size() == 1 && PayOrderEnums.PAY_ORDER_FUND_STATUS.FUNDING.getCode().equals(fundStatusSet.get(0))) {
                return;
            }
            updatePayFund(profitOrderResultDto.getRefundOrderFundList(), refundOrderFund);
        });
    }

    @Override
    public void syncDelayAcctOrderStatus() {
        log.info("延时分账订单同步");
        PayOrderFundQueryDto payOrderFundQueryDto = new PayOrderFundQueryDto();
        payOrderFundQueryDto.setFundProcessType(PayOrderEnums.FUND_PROCESS_TYPE.DELAY_TIME.getCode());
        payOrderFundQueryDto.setFundStatus(PayOrderEnums.PAY_ORDER_FUND_STATUS.SUCCESS.getCode());
        payOrderFundQueryDto.setFundType(CommonEnum.YES_NO_TYPE.NO.getCode());
        List<OrderFundDO> payOrderFundList = payOrderFundService.queryPayAcctInfoList(payOrderFundQueryDto);
        if(CollUtil.isNotEmpty(payOrderFundList)){
            PayOrderDO payOrderDO = null;
            for(OrderFundDO orderFundDO:payOrderFundList){
                payOrderDO = payOrderService.queryPayOrder(orderFundDO.getPayOrderNo());
                // 请求第三方
                channelProfitOrderGateway.finishAcctOrder(payOrderDO, orderFundDO);
            }
        }
    }

    @Override
    public CommonResult<String> settleConfirm(List<String> payOrderNos) {
        log.info("订单资金结算");
        if(CollUtil.isEmpty(payOrderNos)){
            return CommonResult.success();
        }
        for(String payOrderNo:payOrderNos){
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderNo);
            CommonResult<String> commonResult = channelProfitOrderGateway.settleConfirm(payOrderDO);
            if(commonResult.isSuccess()){
                log.info("订单资金结算 成功, payOrderNo:{}",payOrderNo);
            }else{
                log.info("订单资金结算 失败, payOrderNo:{} errMsg:{}",payOrderNo,commonResult.getMsg());
            }
        }
        return CommonResult.success();
    }

    List<OrderFundDetailDO> updatePayFund(List<OrderFundDetailDO> orderFunds, OrderFundDO orderFundDO) {
        if (CollectionUtils.isEmpty(orderFunds)) {
            return payOrderFundService.queryAcctDetailInfo(orderFundDO.getBatchNo());
        }
        OrderFundDto orderFundDto = payOrderFundService.updatePayFund(orderFunds, orderFundDO.getBatchNo());
        OrderFundDO orderFund = orderFundDto.getOrderFund();
        if (orderFund != null) {
            log.info("分账订单状态结束,进行通知 payOrderNo:{}", orderFund.getPayOrderNo());
            // 发送通知
            if (StringUtils.hasText(orderFund.getNotifyUrl())) {
                orderNotifyHandler.orderNotify(orderFund.getBatchNo(), 1,PayOrderEnums.ORDER_STATUS_TYPE.FUND_ORDER_STATUS);
            }
            else {
                log.info("分账订单状态结束,没有填写回调通知地址,结束通知");
            }
        }
        return orderFundDto.getOrderFundDetailList();
    }
}
